home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / fscheck / checkdir.c < prev    next >
C/C++ Source or Header  |  1990-11-02  |  44KB  |  1,581 lines

  1. /* 
  2.  * checkdir.c --
  3.  *
  4.  *    Routines to allow moving through a files block pointers.
  5.  *
  6.  * Copyright 1989 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/cmds/fscheck/RCS/checkdir.c,v 1.30 90/11/01 23:28:33 jhh Exp $ SPRITE (Berkeley)";
  18. #endif not lint
  19.  
  20. #include "option.h"
  21. #include "fscheck.h"
  22. #include "list.h"
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <ctype.h>
  26.  
  27. static    int        adding = 0;
  28. extern    int         writeDisk;
  29. static    char        pathName[FS_MAX_PATH_NAME_LENGTH];
  30. static    FdInfo        *descInfoArray;
  31. static    int    
  32. lostFoundFileNum = -1;
  33. extern    int        patchRoot;
  34. int            outputFileNum = -1;
  35. int            partFID;
  36. Ofs_DomainHeader        *domainPtr;
  37.  
  38. void            CheckDirEntry();
  39. static void        CheckDir();
  40. static ReturnStatus    AddToDirectory();
  41.  
  42. Fsdm_FileDescriptor    *rootFDPtr;
  43. Fsdm_FileDescriptor    *lostFoundFDPtr;
  44.  
  45. extern int verbose;
  46.  
  47. #define DIRFULL 2
  48.  
  49.  
  50. /*
  51.  *----------------------------------------------------------------------
  52.  *
  53.  * FetchFileDesc --
  54.  *
  55.  *    Return a file descriptor.
  56.  *
  57.  * Results:
  58.  *    1 if the file descriptor is successfully read or 0 if the descriptor 
  59.  *    was unreadable.
  60.  *
  61.  * Side effects:
  62.  *    A file descriptor may be allocated.
  63.  *
  64.  *----------------------------------------------------------------------
  65.  */
  66. int
  67. FetchFileDesc(fdNum, fdPtrPtr)
  68.     int            fdNum;        /* Number of descriptor to fetch. */
  69.     Fsdm_FileDescriptor    **fdPtrPtr;    /* Where to store ptr to descriptor. */
  70. {
  71.     ModListElement    *modElemPtr;
  72.     RelocListElement    *relocElemPtr;
  73.     static char        block[FS_BLOCK_SIZE];
  74.     int            blockNum;
  75.     int            offset;
  76.  
  77.     descInfoArray[fdNum].flags &= ~FD_MODIFIED;
  78.  
  79.     if (descInfoArray[fdNum].flags & FD_UNREADABLE) {
  80.     return(0);
  81.     }
  82.     if (descInfoArray[fdNum].flags & FD_RELOCATE) {
  83.     LIST_FORALL(relocList, (List_Links *)relocElemPtr) {
  84.         if (relocElemPtr->origFdNum == fdNum) {
  85.         *fdPtrPtr = relocElemPtr->fdPtr;
  86.         return(1);
  87.         }
  88.     }
  89.     Output(stderr, "FetchFileDesc: FD not found in relocate list.\n");
  90.     abort();
  91.     }
  92.     if (descInfoArray[fdNum].flags & ON_MOD_LIST) {
  93.     LIST_FORALL(modList, (List_Links *)modElemPtr) {
  94.         if (modElemPtr->fdNum == fdNum) {
  95.         *fdPtrPtr = modElemPtr->fdPtr;
  96.         return(1);
  97.         }
  98.     }
  99.     Output(stderr, "FetchFileDesc: FD not found in mod list.\n");
  100.     abort();
  101.     }
  102.     blockNum = domainPtr->fileDescOffset + fdNum / FSDM_FILE_DESC_PER_BLOCK;
  103.     offset = (fdNum & (FSDM_FILE_DESC_PER_BLOCK - 1)) * FSDM_MAX_FILE_DESC_SIZE;
  104.     if (Disk_BlockRead(partFID, domainPtr, blockNum, 1, 
  105.                (Address) block) < 0) {
  106.     OutputPerror("FetchFileDesc: Read failed on previously readable block");
  107.     exit(EXIT_READ_FAILURE);
  108.     }
  109.     Alloc(*fdPtrPtr,Fsdm_FileDescriptor,1);
  110.     if (tooBig) {
  111.     return 0;
  112.     }
  113.     bcopy((Address)&block[offset], (Address)*fdPtrPtr, 
  114.       sizeof(Fsdm_FileDescriptor));
  115.     return(1);
  116. }
  117.  
  118.  
  119. /*
  120.  *----------------------------------------------------------------------
  121.  *
  122.  * StoreFileDesc --
  123.  *
  124.  *    Store a file descriptor on disk.
  125.  *
  126.  * Results:
  127.  *    None.
  128.  *
  129.  * Side effects:
  130.  *    An FdCheckInfo struct is allocated.
  131.  *
  132.  *----------------------------------------------------------------------
  133.  */
  134. void
  135. StoreFileDesc(fdNum, fdPtr)
  136.     int            fdNum;
  137.     Fsdm_FileDescriptor    *fdPtr;
  138. {
  139.     ModListElement    *modElemPtr;
  140.  
  141.     if (descInfoArray[fdNum].flags & FD_MODIFIED) {
  142.     if (descInfoArray[fdNum].flags & ON_MOD_LIST) {
  143.         LIST_FORALL(modList, (List_Links *)modElemPtr) {
  144.         if (modElemPtr->fdNum == fdNum) {
  145.             /*
  146.              * The old fd may be in use on another list so we can't
  147.              * free it, but it may become unreferenced. 
  148.              */
  149.             modElemPtr->fdPtr = fdPtr;
  150.             return;
  151.         }
  152.         }
  153.         Output(stderr, "StoreFileDesc: FD not found in list.\n");
  154.         abort();
  155.     } else {
  156.         ModListElement    *modElemPtr;
  157.  
  158.         Alloc(modElemPtr,ModListElement,1);
  159.         if (tooBig) {
  160.         return;
  161.         }
  162.         descInfoArray[fdNum].flags |= ON_MOD_LIST;
  163.         modElemPtr->fdNum = fdNum;
  164.         modElemPtr->fdPtr = fdPtr;
  165.         List_Insert((List_Links *)modElemPtr, LIST_ATREAR(modList));
  166.     }
  167.     }
  168. }
  169.  
  170. /*
  171.  *----------------------------------------------------------------------
  172.  *
  173.  * MakePtrAccessible --
  174.  *
  175.  *    Make the pointer to the directory entry accessible.
  176.  *
  177.  * Results:
  178.  *    None.
  179.  *
  180.  * Side effects:
  181.  *    *indexInfoPtr modified.
  182.  *
  183.  *----------------------------------------------------------------------
  184.  */
  185. static int
  186. MakePtrAccessible(indexInfoPtr)
  187.     register    DirIndexInfo *indexInfoPtr;
  188. {
  189.     register int         *blockAddrPtr;
  190.     register Fsdm_FileDescriptor    *fdPtr;
  191.  
  192.     fdPtr = indexInfoPtr->fdPtr;
  193.  
  194.     blockAddrPtr = &indexInfoPtr->blockAddr;
  195.  
  196.     if (indexInfoPtr->indexType == INDIRECT) {
  197.     *blockAddrPtr = fdPtr->indirect[0];
  198.     } else {
  199.     *blockAddrPtr = fdPtr->indirect[1];
  200.     }
  201.  
  202.     /*
  203.      * Read first level block in.
  204.      */
  205.     if (indexInfoPtr->firstBlockNil) {
  206.     if (*blockAddrPtr == FSDM_NIL_INDEX) {
  207.         return(1);
  208.     }
  209.     if (Disk_FragRead(partFID, domainPtr,
  210.               *blockAddrPtr, FS_FRAGMENTS_PER_BLOCK,
  211.               indexInfoPtr->firstBlock) < 0) {
  212.         Output(stderr,"MakePtrAccessible: Read (1) failed block %d\n",
  213.                *blockAddrPtr);
  214.         return(0);
  215.     }
  216.     indexInfoPtr->firstBlockNil = 0;
  217.     }
  218.  
  219.     *blockAddrPtr = *(int *) (indexInfoPtr->firstBlock +
  220.                   sizeof(int) * indexInfoPtr->firstIndex);
  221.     if (indexInfoPtr->indexType == INDIRECT) {
  222.     return(1);
  223.     }
  224.  
  225.     /*
  226.      * Read second level block in.
  227.      */
  228.     if (*blockAddrPtr != FSDM_NIL_INDEX) {
  229.     if (Disk_FragRead(partFID, domainPtr,
  230.               *blockAddrPtr, FS_FRAGMENTS_PER_BLOCK,
  231.               indexInfoPtr->secondBlock) < 0) {
  232.         Output(stderr,"MakePtrAccessible: Read (2) failed block %d\n",
  233.                *blockAddrPtr);
  234.         return(0);
  235.     }
  236.     indexInfoPtr->secondBlockNil = 0;
  237.     *blockAddrPtr = *(int *) (indexInfoPtr->secondBlock +
  238.                   sizeof(int) * indexInfoPtr->secondIndex);
  239.     }
  240.     return(1);
  241. }
  242.  
  243.  
  244. /*
  245.  *----------------------------------------------------------------------
  246.  *
  247.  * GetFirstIndex --
  248.  *
  249.  *    Initialize the index structure.  This will set up the index info
  250.  *    structure so that it contains a pointer to the desired block pointer.
  251.  *
  252.  * Results:
  253.  *    1 if could set up the index, 0 if could not.
  254.  *
  255.  * Side effects:
  256.  *    The index structure is initialized.
  257.  *
  258.  *----------------------------------------------------------------------
  259.  */
  260. static int
  261. GetFirstIndex(blockNum, indexInfoPtr)
  262.     int                  blockNum;      /* Where to start indexing. */
  263.     register DirIndexInfo     *indexInfoPtr; /* Index structure to initialize.*/
  264. {
  265.     int            indirectBlock;
  266.     Fsdm_FileDescriptor    *fdPtr;
  267.  
  268.     indexInfoPtr->firstBlockNil = 1;
  269.     indexInfoPtr->secondBlockNil = 1;
  270.     indexInfoPtr->blockNum = blockNum;
  271.     indexInfoPtr->dirDirty = 0;
  272.  
  273.     fdPtr = indexInfoPtr->fdPtr;
  274.  
  275.     if (blockNum < FSDM_NUM_DIRECT_BLOCKS) {
  276.     /*
  277.      * This is a direct block.
  278.      */
  279.     indexInfoPtr->indexType = DIRECT;
  280.     indexInfoPtr->firstIndex = blockNum;
  281.     indexInfoPtr->blockAddr = fdPtr->direct[blockNum];
  282.     return(1);
  283.     }
  284.  
  285.     /*
  286.      * Is an indirect block.
  287.      */
  288.     blockNum -= FSDM_NUM_DIRECT_BLOCKS;
  289.     indirectBlock = blockNum / FSDM_INDICES_PER_BLOCK;
  290.     if (indirectBlock == 0) {
  291.     /*
  292.      * This is a singly indirect block.
  293.      */
  294.     indexInfoPtr->indexType = INDIRECT;
  295.     indexInfoPtr->firstIndex = blockNum;
  296.     } else {
  297.     /*
  298.      * This a doubly indirect block.
  299.      */
  300.     indexInfoPtr->indexType = DBL_INDIRECT;
  301.     indexInfoPtr->firstIndex = indirectBlock - 1;
  302.     indexInfoPtr->secondIndex = blockNum -
  303.                     indirectBlock * FSDM_INDICES_PER_BLOCK;
  304.     }
  305.  
  306.     /*
  307.      * Finish off by making the block pointer accessible.  This may include
  308.      * reading indirect blocks into the cache.
  309.      */
  310.     return(MakePtrAccessible(indexInfoPtr));
  311. }
  312.  
  313.  
  314. /*
  315.  *----------------------------------------------------------------------
  316.  *
  317.  * GetNextIndex --
  318.  *
  319.  *    Put the correct pointers in the index structure to access the
  320.  *    block after the current block.
  321.  *
  322.  * Results:
  323.  *    None.
  324.  *
  325.  * Side effects:
  326.  *    The allocation structure is modified.
  327.  *
  328.  *----------------------------------------------------------------------
  329.  */
  330. static int
  331. GetNextIndex(indexInfoPtr)
  332.     register DirIndexInfo *indexInfoPtr; /* Index structure to set up. */
  333. {
  334.     int            accessible = 0;
  335.     register Fsdm_FileDescriptor    *fdPtr;
  336.  
  337.     fdPtr = indexInfoPtr->fdPtr;
  338.  
  339.     indexInfoPtr->blockNum++;
  340.     indexInfoPtr->dirDirty = 0;
  341.  
  342.     /*
  343.      * Determine whether we are now in direct, indirect or doubly indirect
  344.      * blocks.
  345.      */
  346.     switch (indexInfoPtr->indexType) {
  347.     case DIRECT:
  348.         if (indexInfoPtr->blockNum < FSDM_NUM_DIRECT_BLOCKS) {
  349.         /*
  350.          * Still in the direct blocks.
  351.          */
  352.         indexInfoPtr->firstIndex++;
  353.         indexInfoPtr->blockAddr = 
  354.                 fdPtr->direct[indexInfoPtr->firstIndex];
  355.         accessible = 1;
  356.         } else {
  357.         /*
  358.          * Moved into indirect blocks.
  359.          */
  360.         indexInfoPtr->indexType = INDIRECT;
  361.         indexInfoPtr->firstIndex = 0;
  362.         }
  363.         break;
  364.     case INDIRECT:
  365.         if (indexInfoPtr->blockNum < FSDM_NUM_DIRECT_BLOCKS +
  366.             FSDM_INDICES_PER_BLOCK) {
  367.         /*
  368.          * Still in singly indirect blocks.
  369.          */
  370.         indexInfoPtr->firstIndex++;
  371.         indexInfoPtr->blockAddr = *(int *) (indexInfoPtr->firstBlock +
  372.                   sizeof(int) * indexInfoPtr->firstIndex);
  373.         accessible = 1;
  374.         break;
  375.        } else {
  376.         /*
  377.          * Moved into doubly indirect blocks.
  378.          */
  379.         indexInfoPtr->firstIndex = 0;
  380.         indexInfoPtr->secondIndex = 0;
  381.         indexInfoPtr->indexType = DBL_INDIRECT;
  382.         /*
  383.          * Free up the pointer block.
  384.          */
  385.         indexInfoPtr->firstBlockNil = 1;
  386.         }
  387.         break;
  388.     case DBL_INDIRECT:
  389.         indexInfoPtr->secondIndex++;
  390.         if (indexInfoPtr->secondIndex == FSDM_INDICES_PER_BLOCK) {
  391.         indexInfoPtr->firstIndex++;
  392.         indexInfoPtr->secondIndex = 0;
  393.         indexInfoPtr->secondBlockNil = 1;
  394.         } else {
  395.         indexInfoPtr->blockAddr = *(int *) (indexInfoPtr->secondBlock +
  396.                   sizeof(int) * indexInfoPtr->secondIndex);
  397.         accessible = 1;
  398.         }
  399.         break;
  400.     }
  401.  
  402.     /*
  403.      * Make the block pointers accessible if necessary.
  404.      */
  405.     if (!accessible) {
  406.     return(MakePtrAccessible(indexInfoPtr));
  407.     } else {
  408.     return(1);
  409.     }
  410. }
  411.  
  412.  
  413. /*
  414.  *----------------------------------------------------------------------
  415.  *
  416.  * OpenDir --
  417.  *
  418.  *    Set up the structure to allow moving through the given directory.
  419.  *
  420.  * Results:
  421.  *    None.
  422.  *
  423.  * Side effects:
  424.  *    The index structure is set up and *dirEntryPtrPtr set to point to
  425.  *    the first directory entry.
  426.  *
  427.  *----------------------------------------------------------------------
  428.  */
  429. void
  430. OpenDir(fdPtr, fdInfoPtr, indexInfoPtr, dirEntryPtrPtr)
  431.     Fsdm_FileDescriptor    *fdPtr;        /* The file descriptor for the
  432.                      * directory. */
  433.     FdInfo        *fdInfoPtr;    /* Descriptor status info for the
  434.                      * directory. */
  435.     DirIndexInfo     *indexInfoPtr;    /* Index info struct */
  436.     Fslcl_DirEntry        **dirEntryPtrPtr; /* Where to return a pointer to
  437.                        * the first directory entry. */
  438. {
  439.     int            fragsToRead;
  440.  
  441.     if (fdPtr->lastByte == -1) {
  442.     /*
  443.      * Empty directory.
  444.      */
  445.     *dirEntryPtrPtr = (Fslcl_DirEntry *) NULL;
  446.     return;
  447.     } else if ((fdPtr->lastByte + 1) % FSLCL_DIR_BLOCK_SIZE != 0) {
  448.     Output(stderr,
  449.     "Directory not multiple of directory block size. Directory corrected.\n");
  450.     foundError = 1;
  451.     fdPtr->lastByte = (fdPtr->lastByte & ~(FSLCL_DIR_BLOCK_SIZE - 1)) +
  452.                 FSLCL_DIR_BLOCK_SIZE - 1;
  453.     fdInfoPtr->flags |= FD_MODIFIED;
  454.     }
  455.     /*
  456.      * Initialize the index structure.
  457.      */
  458.     indexInfoPtr->fdPtr = fdPtr;
  459.     indexInfoPtr->fdInfoPtr = fdInfoPtr;
  460.     if (!GetFirstIndex(0, indexInfoPtr)) {
  461.     Output(stderr, "OpenDir: Error setting up index\n");
  462.     *dirEntryPtrPtr = (Fslcl_DirEntry *) NULL;
  463.     return;
  464.     }
  465.     /*
  466.      * Read in the first directory block.
  467.      */
  468.     if (fdPtr->lastByte >= FS_BLOCK_SIZE - 1) {
  469.     fragsToRead = FS_FRAGMENTS_PER_BLOCK;
  470.     } else {
  471.     fragsToRead = fdPtr->lastByte / FS_FRAGMENT_SIZE + 1;
  472.     }
  473.     indexInfoPtr->numFrags = fragsToRead;
  474.     if (Disk_FragRead(partFID, domainPtr,
  475.               indexInfoPtr->blockAddr + 
  476.               domainPtr->dataOffset * FS_FRAGMENTS_PER_BLOCK, 
  477.               fragsToRead, indexInfoPtr->dirBlock) < 0) {
  478.     Output(stderr, "OpenDir: Read failed block %d\n",
  479.                indexInfoPtr->blockAddr + 
  480.                        domainPtr->dataOffset * FS_FRAGMENTS_PER_BLOCK);
  481.     *dirEntryPtrPtr = (Fslcl_DirEntry *) NULL;
  482.     return;
  483.     } 
  484.     indexInfoPtr->dirOffset = 0;
  485.     *dirEntryPtrPtr = (Fslcl_DirEntry *) indexInfoPtr->dirBlock;
  486. }
  487.  
  488.  
  489. /*
  490.  *----------------------------------------------------------------------
  491.  *
  492.  * NextDirEntry --
  493.  *
  494.  *    Return a pointer to the next directory entry.
  495.  *
  496.  * Results:
  497.  *    None.
  498.  *
  499.  * Side effects:
  500.  *    The index structure is modified and *dirEntryPtrPtr set to point
  501.  *    to the next directory entry.
  502.  *
  503.  *----------------------------------------------------------------------
  504.  */
  505. void
  506. NextDirEntry(indexInfoPtr, dirEntryPtrPtr)
  507.     DirIndexInfo     *indexInfoPtr;
  508.     Fslcl_DirEntry        **dirEntryPtrPtr;
  509. {
  510.     int            firstDirByte;
  511.     int            lastByte;
  512.     Fslcl_DirEntry        *dirEntryPtr;
  513.     int            fragsToRead;
  514.  
  515.     dirEntryPtr = *dirEntryPtrPtr;
  516.     indexInfoPtr->dirOffset += dirEntryPtr->recordLength;
  517.     lastByte = indexInfoPtr->fdPtr->lastByte;
  518.     firstDirByte = 
  519.      indexInfoPtr->dirOffset + indexInfoPtr->blockNum * FS_BLOCK_SIZE;
  520.     if (firstDirByte == lastByte + 1) {
  521.     /*
  522.      * We reached the end of the directory.  Write out the directory
  523.      * block if necessary.
  524.      */
  525.     *dirEntryPtrPtr = (Fslcl_DirEntry *) NULL;
  526.     if (indexInfoPtr->dirDirty && writeDisk) {
  527.         if (Disk_FragWrite(partFID, domainPtr,
  528.                   indexInfoPtr->blockAddr + 
  529.                   domainPtr->dataOffset * 
  530.                   FS_FRAGMENTS_PER_BLOCK, 
  531.                   indexInfoPtr->numFrags, 
  532.                   indexInfoPtr->dirBlock) < 0) {
  533.         Output(stderr, "NextDirEntry: Write failed block %d\n",
  534.                    indexInfoPtr->blockAddr + 
  535.                     domainPtr->dataOffset * FS_FRAGMENTS_PER_BLOCK);
  536.         }
  537.     }
  538.     return;
  539.     }
  540.  
  541.     if (indexInfoPtr->dirOffset < FS_BLOCK_SIZE) {
  542.     /*
  543.      * The next directory entry is in the current block.
  544.      */
  545.     dirEntryPtr = 
  546.          (Fslcl_DirEntry *) &(indexInfoPtr->dirBlock[indexInfoPtr->dirOffset]);
  547.     } else {
  548.     /*
  549.      * Have to move to the next directory block.  Write out the current
  550.      * block if necessary.
  551.      */
  552.     if (indexInfoPtr->dirDirty && writeDisk) {
  553.         if (Disk_FragWrite(partFID, domainPtr,
  554.                   indexInfoPtr->blockAddr + 
  555.                   domainPtr->dataOffset * 
  556.                   FS_FRAGMENTS_PER_BLOCK, 
  557.                   indexInfoPtr->numFrags, 
  558.                   indexInfoPtr->dirBlock) < 0) {
  559.         Output(stderr, "NextDirEntry: Write (2) failed block %d\n",
  560.                    indexInfoPtr->blockAddr + 
  561.                     domainPtr->dataOffset * FS_FRAGMENTS_PER_BLOCK);
  562.         *dirEntryPtrPtr = (Fslcl_DirEntry *) NULL;
  563.         return;
  564.         }
  565.     }
  566.     if (!GetNextIndex(indexInfoPtr)) {
  567.         Output(stderr, "NextDirEntry: Get index failed\n");
  568.         *dirEntryPtrPtr = (Fslcl_DirEntry *) NULL;
  569.         return;
  570.     }
  571.     if (lastByte - firstDirByte + 1 >= FS_BLOCK_SIZE ||
  572.         indexInfoPtr->blockNum >= FSDM_NUM_DIRECT_BLOCKS) {
  573.         fragsToRead = FS_FRAGMENTS_PER_BLOCK;
  574.     } else {
  575.         fragsToRead = (lastByte - firstDirByte) / FS_FRAGMENT_SIZE + 1;
  576.     }
  577.     indexInfoPtr->numFrags = fragsToRead;
  578.     if (Disk_FragRead(partFID, domainPtr,
  579.               indexInfoPtr->blockAddr + 
  580.               domainPtr->dataOffset * 
  581.               FS_FRAGMENTS_PER_BLOCK, 
  582.               fragsToRead, indexInfoPtr->dirBlock) < 0) {
  583.         Output(stderr, "NextDirEntry: Read failed block %d\n",
  584.                 indexInfoPtr->blockAddr + 
  585.                 domainPtr->dataOffset * FS_FRAGMENTS_PER_BLOCK);
  586.         *dirEntryPtrPtr = (Fslcl_DirEntry *) NULL;
  587.         return;
  588.     }
  589.     indexInfoPtr->dirOffset = 0;
  590.     dirEntryPtr = (Fslcl_DirEntry *) indexInfoPtr->dirBlock;
  591.     }
  592.  
  593.     *dirEntryPtrPtr = dirEntryPtr;
  594. }
  595.  
  596. static    DirIndexInfo    lostDirIndex;
  597. static  Fslcl_DirEntry    *lostDirEntryPtr;
  598.  
  599. static    DirIndexInfo    rootDirIndex;
  600. static  Fslcl_DirEntry    *rootDirEntryPtr;
  601. static    List_Links    orphanDirListHdr;
  602. static  List_Links    *orphanDirList = &orphanDirListHdr;
  603. typedef struct DirList {
  604.     List_Links    links;
  605.     int        dirNumber;
  606. } DirList;
  607.  
  608. /*
  609.  *----------------------------------------------------------------------
  610.  *
  611.  * CloseDir --
  612.  *
  613.  *    Flushes the current directory block to disk, if necessary.
  614.  *
  615.  * Results:
  616.  *    None.
  617.  *
  618.  * Side effects:
  619.  *    The index structure is modified and *dirEntryPtrPtr set to point
  620.  *    to the next directory entry.
  621.  *
  622.  *----------------------------------------------------------------------
  623.  */
  624. static void
  625. CloseDir(indexInfoPtr)
  626.     DirIndexInfo     *indexInfoPtr;
  627. {
  628.  
  629.     if (indexInfoPtr->dirDirty && writeDisk) {
  630.     if (Disk_FragWrite(partFID, domainPtr,
  631.               indexInfoPtr->blockAddr + 
  632.               domainPtr->dataOffset * 
  633.               FS_FRAGMENTS_PER_BLOCK, 
  634.               indexInfoPtr->numFrags, 
  635.               indexInfoPtr->dirBlock) < 0) {
  636.         Output(stderr, "CloseDir: Write (2) failed block %d\n",
  637.                indexInfoPtr->blockAddr + 
  638.                 domainPtr->dataOffset * FS_FRAGMENTS_PER_BLOCK);
  639.         return;
  640.     }
  641.     }
  642. }
  643.  
  644.  
  645. /*
  646.  *----------------------------------------------------------------------
  647.  *
  648.  * CheckDirTree --
  649.  *
  650.  *    Traverse the directory tree taking care of unreferenced files and
  651.  *    ensuring that link counts are correct.
  652.  *
  653.  * Results:
  654.  *    A return status.
  655.  *
  656.  * Side effects:
  657.  *    None.
  658.  *
  659.  *----------------------------------------------------------------------
  660.  */
  661. void
  662. CheckDirTree(partFIDParm, domainParmPtr, descInfoParm,fdBitmapPtr, bitmapPtr)
  663.     int            partFIDParm;
  664.     Ofs_DomainHeader    *domainParmPtr;
  665.     FdInfo        *descInfoParm;
  666.     u_char        *fdBitmapPtr;
  667.     u_char        *bitmapPtr;
  668. {
  669.     register    int    i;
  670.     register FdInfo    *fdInfoPtr;
  671.     Fslcl_DirEntry        *dirEntryPtr;
  672.     DirIndexInfo    dirIndex;
  673.     int            lostRootDirNum = -1;
  674.     int            unrefFiles = 0;
  675.     int            linkCountsCorrected = 0;
  676.     int            entryNum;
  677.     char        newFileName[100];
  678.     int            offset;
  679.     int            outputFileLength;
  680.     int            notAdded;
  681.  
  682.     partFID = partFIDParm;
  683.     domainPtr = domainParmPtr;
  684.     descInfoArray = descInfoParm;
  685.  
  686.     /*
  687.      * Check the root directory for consistency.
  688.      */
  689.     if (!FetchFileDesc(FSDM_ROOT_FILE_NUMBER, &rootFDPtr)) {
  690.     Output(stderr, "Unable to fetch file descriptor for root");
  691.     exit(EXIT_HARD_ERROR);
  692.     }
  693.  
  694.     if ((rootFDPtr->flags & FSDM_FD_FREE) ||
  695.     rootFDPtr->fileType != FS_DIRECTORY ||
  696.     rootFDPtr->magic != FSDM_FD_MAGIC ||
  697.     rootFDPtr->lastByte == -1) {
  698.     char *fileName;
  699.  
  700.     Output(stderr, "Root directory corrupted\n");
  701.     if (!patchRoot) {
  702.         exit(EXIT_HARD_ERROR);
  703.     } 
  704.     /*
  705.      * On 5/10/88 the root of a disk (/sprite) was overwritten.  It was
  706.      * patched by looking for directories with a ".." entry that
  707.      * referenced root, fileNumber == 2, and putting them into the
  708.      * root just like other orphans are put into lost+found.
  709.      */
  710.     Output(stderr, "Attempting to re-create the root\n");
  711.     lostRootDirNum = FSDM_ROOT_FILE_NUMBER;
  712.     List_Init(orphanDirList);
  713.     lostFoundFileNum = FSDM_ROOT_FILE_NUMBER + 1;
  714.     if (MakeRoot(domainPtr, bitmapPtr, rootFDPtr) != SUCCESS) {
  715.         Output(stderr,"Unable to reinitialize root fd.\n");
  716.         exit(EXIT_HARD_ERROR);
  717.     }
  718.     OpenDir(rootFDPtr, &descInfoArray[FSDM_ROOT_FILE_NUMBER], &rootDirIndex, 
  719.         &rootDirEntryPtr);
  720.     /*
  721.      * Create the "." and ".." entries in the trashed directory.  The
  722.      * above OpenDir call has set up rootDirEntryPtr to reference the
  723.      * first bytes in the directory.
  724.      */
  725.         descInfoArray[FSDM_ROOT_FILE_NUMBER].flags |= FD_ALLOCATED;
  726.     descInfoArray[FSDM_ROOT_FILE_NUMBER].flags |= FD_MODIFIED;
  727.     descInfoArray[FSDM_ROOT_FILE_NUMBER].flags |= IS_A_DIRECTORY;
  728.     MarkFDBitmap(FSDM_ROOT_FILE_NUMBER,fdBitmapPtr);
  729.     StoreFileDesc(FSDM_ROOT_FILE_NUMBER, rootFDPtr);
  730.     fileName = ".";
  731.     rootDirEntryPtr->fileNumber = lostRootDirNum;
  732.     rootDirEntryPtr->nameLength = strlen(fileName);
  733.     rootDirEntryPtr->recordLength =
  734.         Fslcl_DirRecLength(rootDirEntryPtr->nameLength);
  735.     (void)strcpy(rootDirEntryPtr->fileName, fileName);
  736.     offset = rootDirEntryPtr->recordLength;
  737.     NextDirEntry(&rootDirIndex, &rootDirEntryPtr);
  738.  
  739.     fileName = "..";
  740.     rootDirEntryPtr->fileNumber = lostRootDirNum;
  741.     rootDirEntryPtr->nameLength = strlen(fileName);
  742.     rootDirEntryPtr->recordLength = FSLCL_DIR_BLOCK_SIZE - offset;
  743.     (void)strcpy(rootDirEntryPtr->fileName, fileName);
  744.     NextDirEntry(&rootDirIndex, &rootDirEntryPtr);
  745.     for(i = 1; i < FS_BLOCK_SIZE / FSLCL_DIR_BLOCK_SIZE; i++) {
  746.         rootDirEntryPtr->fileNumber = 0;
  747.         rootDirEntryPtr->recordLength = FSLCL_DIR_BLOCK_SIZE;
  748.         rootDirEntryPtr->nameLength = 0;
  749.         NextDirEntry(&rootDirIndex, &rootDirEntryPtr);
  750.     }
  751.     rootDirIndex.dirDirty = 1;
  752.     CloseDir(&rootDirIndex);
  753.     /*
  754.      * If the root is corrupted then don't set the checked bit in the
  755.      * summary sector. I'm kind of paranoid about the above code
  756.      * working correctly.
  757.      */
  758.     setCheckedBit = FALSE;
  759.     }
  760.     OpenDir(rootFDPtr, &descInfoArray[FSDM_ROOT_FILE_NUMBER], &dirIndex, 
  761.         &dirEntryPtr);
  762.     if (dirEntryPtr == (Fslcl_DirEntry *)NULL) {
  763.     exit(EXIT_HARD_ERROR);
  764.     }
  765.  
  766.     (void)strcpy(pathName, "/");
  767.     entryNum = 0;
  768.     if (outputFileName != NULL) {
  769.     outputFileLength = strlen(outputFileName);
  770.     }
  771.     while (dirEntryPtr != (Fslcl_DirEntry *) NULL) {
  772.     /*
  773.      * Go through the root directory checking each directory entry.
  774.      */
  775.     CheckDirEntry(entryNum, &dirIndex, dirEntryPtr);
  776.     if (dirEntryPtr->nameLength > 0 && 
  777.         strncmp("lost+found", dirEntryPtr->fileName,
  778.             dirEntryPtr->nameLength)  == 0) {
  779.         lostFoundFileNum = dirEntryPtr->fileNumber;
  780.     } else if (rawOutput && outputFileName != NULL &&
  781.         (dirEntryPtr->nameLength == outputFileLength) && 
  782.         strncmp(outputFileName, dirEntryPtr->fileName, outputFileLength)
  783.         == 0) {
  784.         outputFileNum = dirEntryPtr->fileNumber;
  785.     }
  786.     NextDirEntry(&dirIndex, &dirEntryPtr);
  787.     entryNum++;
  788.     }
  789.     CloseDir(&dirIndex);
  790.     if (tooBig) {
  791.     return;
  792.     }
  793.  
  794.     if (lostFoundFileNum == -1) {
  795.     Output(stderr, "lost+found missing from root\n");
  796.     lostFoundFileNum = -1;
  797.     } else {
  798.     /*
  799.      * Make sure that lost and found is consistent.
  800.      */
  801.     if (!FetchFileDesc(lostFoundFileNum, &lostFoundFDPtr)) {
  802.         Output(stderr, "Unable to fetch file descriptor for lost+found");
  803.         exit(EXIT_HARD_ERROR);
  804.     }
  805.  
  806.     (void)strcpy(pathName, "/lost+found/");
  807.     fdInfoPtr = &descInfoArray[lostFoundFileNum];
  808.     if (lostFoundFDPtr->fileType != FS_DIRECTORY) {
  809.         Output(stderr,
  810.          "Lost+found isn't a directory!  Should remove and recreate.\n");
  811.         lostFoundFileNum = -1;
  812.     } else {
  813.         int    dirOK;
  814.  
  815.         CheckDir(lostFoundFileNum, lostFoundFDPtr, fdInfoPtr,
  816.             FSDM_ROOT_FILE_NUMBER, lostRootDirNum,    &dirOK);
  817.         if (dirOK) {
  818.         OpenDir(lostFoundFDPtr, fdInfoPtr, &lostDirIndex,
  819.                  &lostDirEntryPtr);
  820.         if (lostDirEntryPtr == (Fslcl_DirEntry *)NULL) {
  821.             Output(stderr, "Could not open lost+found\n");
  822.             lostFoundFileNum = -1;
  823.         } else {
  824.             descInfoArray[lostFoundFileNum].flags |= FD_SEEN;
  825.         }
  826.         } else {
  827.         lostFoundFileNum = -1;
  828.         }
  829.     }
  830.     }
  831.     if (tooBig) {
  832.     return;
  833.     }
  834.  
  835.     /*
  836.      * Check all file descriptors.  If we are re-creating the root this
  837.      * has a side-effect of preparing a list of the orphans of the root.
  838.      */
  839.     for (i = 0, fdInfoPtr = descInfoArray;
  840.      i < domainPtr->numFileDesc; 
  841.      i++, fdInfoPtr++) {
  842.     int            dirOK;
  843.     Fsdm_FileDescriptor    *newFDPtr;
  844.  
  845.     if (!(fdInfoPtr->flags & FD_ALLOCATED) ||
  846.          (fdInfoPtr->flags & FD_SEEN) ||
  847.         !(fdInfoPtr->flags & IS_A_DIRECTORY)) {
  848.         continue;
  849.     }
  850.     pathName[0] = '\0';
  851.     if (!FetchFileDesc(i, &newFDPtr)) {
  852.         Output(stderr,
  853.             "Unable to fetch file descriptor for directory <%d>.\n", i);
  854.         continue;
  855.     }
  856.     CheckDir(i, newFDPtr, fdInfoPtr, FSDM_ROOT_FILE_NUMBER,
  857.         lostRootDirNum, &dirOK);
  858.     StoreFileDesc(i, newFDPtr);
  859.     }
  860.  
  861.     if (patchRoot && lostRootDirNum > 0) {
  862.     DirList *dirListPtr;
  863.  
  864.     notAdded = 0;
  865.  
  866.     /*
  867.      * Go through the list of root-orphans, putting them into the root.
  868.      */
  869.     OpenDir(rootFDPtr, &descInfoArray[FSDM_ROOT_FILE_NUMBER], &rootDirIndex, 
  870.         &rootDirEntryPtr);
  871.  
  872.     LIST_FORALL(orphanDirList, (List_Links *)dirListPtr) {
  873.         if (dirListPtr->dirNumber == lostFoundFileNum) {
  874.         (void) strncpy(newFileName,"lost+found",100);
  875.         } else { 
  876.         (void) sprintf(newFileName, "%d", dirListPtr->dirNumber);
  877.         }
  878.         if (AddToDirectory(lostRootDirNum, rootFDPtr, &rootDirIndex,
  879.              &rootDirEntryPtr, dirListPtr->dirNumber,
  880.              newFileName,
  881.              &descInfoArray[dirListPtr->dirNumber]) == DIRFULL) {
  882.         if (notAdded == 0) {
  883.             Output(stderr, 
  884.             "Directory #%d full.  Couldn't insert file.\n", 
  885.             lostRootDirNum);
  886.         }
  887.         notAdded++;
  888.         }
  889.     }
  890.     if (notAdded > 0) {
  891.         Output(stderr, "%d files not added to directory %d.\n", notAdded,
  892.         lostRootDirNum);
  893.     }
  894.     if (rootDirIndex.dirDirty && writeDisk) {
  895.         if (Disk_FragWrite(partFID, domainPtr,
  896.                 rootDirIndex.blockAddr + domainPtr->dataOffset * 
  897.                 FS_FRAGMENTS_PER_BLOCK, rootDirIndex.numFrags, 
  898.                 rootDirIndex.dirBlock) < 0) {
  899.         OutputPerror("CheckDirTree: Write failed");
  900.         exit(EXIT_WRITE_FAILURE);
  901.         }
  902.     }
  903.     }
  904.     if (tooBig) {
  905.     return;
  906.     }
  907.     /*
  908.      * Now go through the file descriptors again this time putting all
  909.      * unreferenced files in the lost and found directory and correcting
  910.      * link counts.
  911.      */
  912.     notAdded = 0;
  913.     for (i = 0, fdInfoPtr = descInfoArray;
  914.      i <= domainPtr->numFileDesc; 
  915.      i++, fdInfoPtr++) {
  916.  
  917.     /*
  918.      * We have to do lost+found last because its link count is changed
  919.      * when directories are added to it.
  920.      */
  921.     if (i == lostFoundFileNum) {
  922.         continue;
  923.     } else if (i == domainPtr->numFileDesc) {
  924.         if (lostFoundFileNum == -1) {
  925.         break;
  926.         }
  927.         i = lostFoundFileNum;
  928.         fdInfoPtr = &descInfoArray[lostFoundFileNum];
  929.     }
  930.     if (!(fdInfoPtr->flags & FD_ALLOCATED) ||
  931.         (fdInfoPtr->flags & FD_UNREADABLE) ||
  932.         i == FSDM_BAD_BLOCK_FILE_NUMBER) {
  933.         continue;
  934.     }
  935.  
  936.     if (!(fdInfoPtr->flags & FD_REFERENCED) && i != FSDM_ROOT_FILE_NUMBER) {
  937.         if (verbose) {
  938.         Output(stderr, "File %d is unreferenced\n", i);
  939.         }
  940.         unrefFiles++;
  941.         foundError = 1;
  942.         fflush(stderr);
  943.         if (lostFoundFileNum != -1) {
  944.         (void) sprintf(newFileName,"%d",i);
  945.         if (AddToDirectory(lostFoundFileNum, lostFoundFDPtr, 
  946.                 &lostDirIndex, &lostDirEntryPtr, i, 
  947.                 newFileName, fdInfoPtr) == DIRFULL) {
  948.             if (notAdded == 0) {
  949.             Output(stderr, 
  950.                 "Directory #%d full.  Couldn't insert file.\n", 
  951.                 lostFoundFileNum);
  952.             }
  953.             notAdded++;
  954.         }
  955.         }
  956.     } else if (fdInfoPtr->newLinkCount != fdInfoPtr->origLinkCount) {
  957.         if (verbose) {
  958.         Output(stderr,
  959.             "Link count corrected for file %d.  Is %d should be %d.\n", 
  960.             i, fdInfoPtr->origLinkCount, fdInfoPtr->newLinkCount);
  961.         }
  962.         linkCountsCorrected++;
  963.         foundError = 1;
  964.         fflush(stderr);
  965.         if (i == FSDM_ROOT_FILE_NUMBER) {
  966.         rootFDPtr->numLinks = fdInfoPtr->newLinkCount;
  967.         fdInfoPtr->flags |= FD_MODIFIED;
  968.         } else if (i == lostFoundFileNum) {
  969.         lostFoundFDPtr->numLinks = fdInfoPtr->newLinkCount;
  970.         fdInfoPtr->flags |= FD_MODIFIED;
  971.         } else {
  972.         Fsdm_FileDescriptor    *fdPtr;
  973.         if (!FetchFileDesc(i, &fdPtr)) {
  974.             Output(stderr,
  975.       "Unable to fetch file descriptor for file <%d> to update link count", i);
  976.         } else {
  977.             fdPtr->numLinks = fdInfoPtr->newLinkCount;
  978.             fdInfoPtr->flags |= FD_MODIFIED;
  979.             StoreFileDesc(i, fdPtr);
  980.         }
  981.         }
  982.     }
  983.     if (i == lostFoundFileNum) {
  984.         break;
  985.     }
  986.     }
  987.     if (notAdded > 0) {
  988.     Output(stderr, "%d files not added to directory %d.\n", notAdded,
  989.         lostFoundFileNum);
  990.     }
  991.  
  992.     if (unrefFiles > 0) {
  993.     Output(stderr, "%d unreferenced files\n", unrefFiles);
  994.     }
  995.     if (linkCountsCorrected) {
  996.     Output(stderr, "%d links counts corrected\n",
  997.                linkCountsCorrected);
  998.     }
  999.  
  1000.     if (lostFoundFileNum != - 1 && lostDirIndex.dirDirty && writeDisk) {
  1001.     if (Disk_FragWrite(partFID, domainPtr,
  1002.             lostDirIndex.blockAddr + domainPtr->dataOffset * 
  1003.                 FS_FRAGMENTS_PER_BLOCK,
  1004.                 lostDirIndex.numFrags, 
  1005.                 lostDirIndex.dirBlock) < 0) {
  1006.         OutputPerror("CheckDirTree: Write failed");
  1007.         exit(EXIT_WRITE_FAILURE);
  1008.     }
  1009.     }
  1010.  
  1011.     StoreFileDesc(FSDM_ROOT_FILE_NUMBER, rootFDPtr);
  1012.     if (lostFoundFileNum != -1) {
  1013.     StoreFileDesc(lostFoundFileNum, lostFoundFDPtr);
  1014.     }
  1015. }
  1016.  
  1017.  
  1018. /*
  1019.  *----------------------------------------------------------------------
  1020.  *
  1021. * CheckDir --
  1022.  *
  1023.  *    Descend the directory tree starting from the given file descriptor.
  1024.  *
  1025.  * Results:
  1026.  *    None.
  1027.  *
  1028.  * Side effects:
  1029.  *    None.
  1030.  *
  1031.  *----------------------------------------------------------------------
  1032.  */
  1033.  
  1034. static void
  1035. CheckDir(fdNum, fdPtr, fdInfoPtr, parentFdNum, lostDirNum, dirOKPtr)
  1036.     int            fdNum;    /* Which file descriptor we are looking
  1037.                        at. */
  1038.     Fsdm_FileDescriptor    *fdPtr;        /* Pointer the file descriptor that
  1039.                      * we are looking at. */
  1040.     FdInfo        *fdInfoPtr;    /* Status of the file desc that we are
  1041.                        looking at. */
  1042.     int            parentFdNum;    /* File descriptor of parent directory.
  1043.     int            lostDirNum;    /* For re-creating trashed directories.
  1044.                      * This routine will add to a list
  1045.                      * of directories that were ref'ed
  1046.                      * by this 'lost directory' */
  1047.     int            *dirOKPtr;    /* Return 1 if the directory is
  1048.                      * not corrupted. */
  1049. {
  1050.     Fslcl_DirEntry     *dirEntryPtr;
  1051.     FdInfo     *newFDInfoPtr;
  1052.     DirIndexInfo dirIndex;
  1053.     int         entryNum;
  1054.     int        nullIndex;
  1055.  
  1056.     fdInfoPtr->flags |= FD_SEEN;
  1057.     *dirOKPtr = 0;
  1058.  
  1059.     /*
  1060.      * Open the directory.
  1061.      */
  1062.     OpenDir(fdPtr, fdInfoPtr, &dirIndex, &dirEntryPtr);
  1063.     nullIndex = strlen(pathName);
  1064.     if (dirEntryPtr == (Fslcl_DirEntry *) NULL) {    
  1065.     Output(stderr, "Empty directory %d %s changed to a file.\n",
  1066.                 fdNum, pathName);
  1067.     foundError = 1;
  1068.     fdPtr->fileType = FS_FILE;
  1069.     fdInfoPtr->flags |= FD_MODIFIED;
  1070.     return;
  1071.     }
  1072.     /*
  1073.      * Go through the directory.
  1074.      */
  1075.     entryNum = 0;
  1076.     if (debug) {
  1077.     Output(stderr,"Working on %s\n",pathName);
  1078.     }
  1079.     do {
  1080.     CheckDirEntry(entryNum, &dirIndex, dirEntryPtr);
  1081.     if (entryNum == 0) {
  1082.         /*
  1083.          * This should be "." and should point to the directory that
  1084.          * we are checking.
  1085.          */
  1086.         if (dirEntryPtr->fileNumber == 0 ||
  1087.         strncmp(".", dirEntryPtr->fileName, 
  1088.             dirEntryPtr->nameLength)  != 0) {
  1089.         Output(stderr,
  1090.             ". missing in directory %d %s.  Changed to a file.\n",
  1091.                    fdNum, pathName);
  1092.         foundError = 1;
  1093.         fdPtr->fileType = FS_FILE;
  1094.         fdInfoPtr->flags |= FD_MODIFIED;
  1095.         fdInfoPtr->flags &= ~IS_A_DIRECTORY;
  1096.         return;
  1097.         }
  1098.         if (dirEntryPtr->fileNumber != fdNum) {
  1099.         Output(stderr, 
  1100.                 ". does not point to self for directory %d %s\n",
  1101.                 fdNum, pathName);
  1102.         foundError = 1;
  1103.         dirEntryPtr->fileNumber = fdNum;
  1104.         dirIndex.dirDirty = 1;
  1105.         }
  1106.         fdInfoPtr->newLinkCount++;
  1107.     } else if (entryNum == 1) {
  1108.         /*
  1109.          * This should be ".."
  1110.          */
  1111.         if (dirEntryPtr->fileNumber == 0 ||
  1112.         strncmp("..", dirEntryPtr->fileName, 
  1113.             dirEntryPtr->nameLength) != 0) {
  1114.         Output(stderr,
  1115.             ".. missing in directory %d %s.  Changed to a file.\n",
  1116.                    fdNum, pathName);
  1117.         foundError = 1;
  1118.         fdPtr->fileType = FS_FILE;
  1119.         fdInfoPtr->flags |= FD_MODIFIED;
  1120.         fdInfoPtr->flags &= ~IS_A_DIRECTORY;
  1121.         return;
  1122.         }
  1123.         if (dirEntryPtr->fileNumber != parentFdNum) {
  1124.         Output(stderr, 
  1125.             ".. in directory %d %s pointed to %d, changed to %d.\n",
  1126.             fdNum, pathName, dirEntryPtr->fileNumber, parentFdNum);
  1127.         foundError = 1;
  1128.         dirEntryPtr->fileNumber = parentFdNum;
  1129.         dirIndex.dirDirty = 1;
  1130.         }
  1131.         /*
  1132.          * Look for orphans of lost directories.
  1133.          */
  1134.         if (lostDirNum > 0 &&
  1135.         dirEntryPtr->fileNumber == lostDirNum &&
  1136.         (fdNum != FSDM_ROOT_FILE_NUMBER ||
  1137.         lostDirNum != FSDM_ROOT_FILE_NUMBER)) {
  1138.         DirList *dirListPtr;
  1139.         Alloc(dirListPtr,DirList,1);
  1140.         if (!tooBig) {
  1141.             dirListPtr->dirNumber = fdNum;
  1142.             Output(stderr, "Found #%d, an orphan of dir #%d\n", 
  1143.                 fdNum, lostDirNum);
  1144.             List_Insert((List_Links *)dirListPtr,
  1145.                 LIST_ATREAR(orphanDirList));
  1146.             fdInfoPtr->flags |= FD_REFERENCED;
  1147.             fdInfoPtr->newLinkCount++;
  1148.         }
  1149.         } else {
  1150.         descInfoArray[dirEntryPtr->fileNumber].newLinkCount++;
  1151.         }
  1152.     } else if (dirEntryPtr->fileNumber != 0) {
  1153.         newFDInfoPtr = &descInfoArray[dirEntryPtr->fileNumber];
  1154.         newFDInfoPtr->newLinkCount++;
  1155.         newFDInfoPtr->flags |= FD_REFERENCED;
  1156.         if (!(newFDInfoPtr->flags & FD_SEEN) &&
  1157.            (newFDInfoPtr->flags & IS_A_DIRECTORY)) {
  1158.         int    dirOK;
  1159.         Fsdm_FileDescriptor    *newFDPtr;
  1160.  
  1161.         /*
  1162.          * Recurse on the directory.
  1163.          */
  1164.         (void)strncat(pathName, dirEntryPtr->fileName,
  1165.                   dirEntryPtr->nameLength);
  1166.         (void)strcat(pathName, "/");
  1167.         if (!FetchFileDesc(dirEntryPtr->fileNumber, &newFDPtr)) {
  1168.             Output(stderr,
  1169.             "Unable to fetch file descriptor for directory <%d>.\n",
  1170.                   dirEntryPtr->fileNumber);
  1171.         } else {
  1172.             CheckDir(dirEntryPtr->fileNumber, newFDPtr, 
  1173.                  newFDInfoPtr, fdNum, lostDirNum, &dirOK);
  1174.             pathName[nullIndex] = '\0';
  1175.             StoreFileDesc(dirEntryPtr->fileNumber, newFDPtr);
  1176.         }
  1177.         } 
  1178.     }
  1179.     NextDirEntry(&dirIndex, &dirEntryPtr);
  1180.     entryNum++;
  1181.     } while (dirEntryPtr != (Fslcl_DirEntry *) NULL);
  1182.  
  1183.     *dirOKPtr = 1;
  1184. }
  1185.  
  1186.  
  1187. /*
  1188.  *----------------------------------------------------------------------
  1189.  *
  1190.  * CheckDirEntry --
  1191.  *
  1192.  *    Perform checks on the current directory entry to make sure that
  1193.  *    it is has not been trashed.
  1194.  *
  1195.  * Results:
  1196.  *    None.
  1197.  *
  1198.  * Side effects:
  1199.  *    The directory may be modified.
  1200.  *
  1201.  *----------------------------------------------------------------------
  1202.  */
  1203.  
  1204. void
  1205. CheckDirEntry(entryNum, dirIndexPtr, dirEntryPtr)
  1206.     int        entryNum;    
  1207.     register    DirIndexInfo    *dirIndexPtr;
  1208.     register    Fslcl_DirEntry    *dirEntryPtr;
  1209. {
  1210.     int            dirBlockOffset;
  1211.     int            lastDirByte;
  1212.     char        buf[FS_MAX_NAME_LENGTH + 1];
  1213.     int            nameLength;
  1214.     register    char    *strPtr;
  1215.     int hadError = 0;
  1216.  
  1217.     dirBlockOffset = dirIndexPtr->dirOffset & (FSLCL_DIR_BLOCK_SIZE - 1);
  1218.     lastDirByte = dirBlockOffset + dirEntryPtr->recordLength;
  1219.  
  1220.     if (dirEntryPtr->fileNumber == 0) {
  1221.     nameLength = 0;
  1222.     } else {
  1223.     nameLength = dirEntryPtr->nameLength;
  1224.     }
  1225.  
  1226.     /*
  1227.      * First check the record length.
  1228.      */
  1229.     if (lastDirByte > FSLCL_DIR_BLOCK_SIZE ||
  1230.     lastDirByte % FSLCL_REC_LEN_GRAIN != 0 || 
  1231.     (FSLCL_DIR_BLOCK_SIZE - lastDirByte < FSLCL_DIR_ENTRY_HEADER &&
  1232.      lastDirByte != FSLCL_DIR_BLOCK_SIZE) ||
  1233.     dirEntryPtr->recordLength < Fslcl_DirRecLength(nameLength) ||
  1234.     dirEntryPtr->recordLength < 0) {
  1235.     Output(stderr,
  1236.     "Bad record length in directory.  Directory entry deleted from %s\n",
  1237.                pathName);
  1238.     foundError = 1;
  1239.     hadError = 1;
  1240.     /*
  1241.      * If the record length is screwed up, extend this record to the end
  1242.      * of the directory block and zap the file number.
  1243.      */
  1244.     dirEntryPtr->recordLength = FSLCL_DIR_BLOCK_SIZE - dirBlockOffset;
  1245.     dirEntryPtr->fileNumber = 0;
  1246.     dirIndexPtr->dirDirty = 1;
  1247.     return;
  1248.     }
  1249.     /*
  1250.      * Check the name length.
  1251.      */
  1252.     if (dirEntryPtr->fileNumber != 0) {
  1253.     int    nameError = 0;
  1254.     nameLength = strnlen(dirEntryPtr->fileName,
  1255.                  dirEntryPtr->recordLength - FSLCL_DIR_ENTRY_HEADER);
  1256.     if (nameLength != dirEntryPtr->nameLength) {
  1257.         bcopy(dirEntryPtr->fileName, buf, nameLength);
  1258.         buf[nameLength] = '\0';
  1259.         Output(stderr,
  1260.         "Name length %d wrong for directory entry: %s. Should be %d.\n", 
  1261.         dirEntryPtr->nameLength, buf, nameLength);
  1262.         foundError = 1;
  1263.         hadError = 1;
  1264.         dirEntryPtr->nameLength = nameLength;
  1265.         dirIndexPtr->dirDirty = 1;
  1266.         dirEntryPtr->recordLength = Fslcl_DirRecLength(nameLength);
  1267.     }
  1268.     /*
  1269.      * Make sure that the name contains printable characters.
  1270.      */
  1271.     strPtr = dirEntryPtr->fileName;
  1272.     while (*strPtr != '\0') {
  1273.         if (*strPtr < 0 || !isprint(*strPtr)) {
  1274.         *strPtr = '?';
  1275.         nameError = 1;
  1276.         }
  1277.         strPtr++;
  1278.     }
  1279.     if (nameError) {
  1280.         dirIndexPtr->dirDirty = 1;
  1281.         Output(stderr,
  1282.           "Non-printable characters in name for file %d in directory %s\n",
  1283.           dirEntryPtr->fileNumber, pathName);
  1284.         foundError = 1;
  1285.         hadError = 1;
  1286.     }
  1287.     }
  1288.  
  1289.     /*
  1290.      * Now check the file number.
  1291.      */
  1292.     if (dirEntryPtr->fileNumber < 0 ||
  1293.         dirEntryPtr->fileNumber >= domainPtr->numFileDesc) {
  1294.     Output(stderr, 
  1295.     "Bad file number in directory.  Directory entry deleted from %s.\n", 
  1296.                pathName);
  1297.     foundError = 1;
  1298.     hadError = 1;
  1299.     dirEntryPtr->fileNumber = 0;
  1300.     dirIndexPtr->dirDirty = 1;
  1301.     /*
  1302.      * Here we want to allow the ".." entry (entryNum = 0) to reference a
  1303.      * non-allocated file descriptor. What we have is an orphan directory so
  1304.      * we shouldn't nuke it just because something bad happened to its parent.
  1305.      */
  1306.     } else if (dirEntryPtr->fileNumber != 0 &&
  1307.               !(descInfoArray[dirEntryPtr->fileNumber].flags & FD_ALLOCATED) &&
  1308.           entryNum != 1)
  1309.           {
  1310.     Output(stderr, 
  1311.         "File %s%s references non-allocated descriptor %d. File Deleted.\n",
  1312.         pathName, dirEntryPtr->fileName,dirEntryPtr->fileNumber);
  1313.     foundError = 1;
  1314.     hadError = 1;
  1315.     dirEntryPtr->fileNumber = 0;
  1316.     dirIndexPtr->dirDirty = 1;
  1317.     }
  1318.     if (!hadError && debug) {
  1319.     Output(stderr,"Entry %s ok.\n",dirEntryPtr->fileName);
  1320.     }
  1321.     if (hadError) {
  1322.     Output(stderr,
  1323.     "Entry %s (%d) now has nameLength %d, recordLength %d, fileNumber %d.\n",
  1324.     dirEntryPtr->fileName, entryNum, dirEntryPtr->nameLength, 
  1325.     dirEntryPtr->recordLength, dirEntryPtr->fileNumber);
  1326.     }
  1327. }
  1328.  
  1329.  
  1330. /*
  1331.  *----------------------------------------------------------------------
  1332.  *
  1333.  * SetDotDot --
  1334.  *
  1335.  *    Make ".." in the given directory point to a given directory.
  1336.  *
  1337.  * Results:
  1338.  *    None.
  1339.  *
  1340.  * Side effects:
  1341.  *    ".." in the given directory is set to point to lost and found.
  1342.  *
  1343.  *----------------------------------------------------------------------
  1344.  */
  1345. static int
  1346. SetDotDot(dirNumber, dirFDPtr, fdPtr, fdInfoPtr)
  1347.     int            dirNumber;
  1348.     Fsdm_FileDescriptor    *dirFDPtr;
  1349.     Fsdm_FileDescriptor    *fdPtr;
  1350.     FdInfo        *fdInfoPtr;
  1351. {
  1352.     Fslcl_DirEntry         *dirEntryPtr;
  1353.     DirIndexInfo     dirIndex;
  1354.  
  1355.     /*
  1356.      * Open the directory.
  1357.      */
  1358.     OpenDir(fdPtr, fdInfoPtr, &dirIndex, &dirEntryPtr);
  1359.     if (dirEntryPtr == (Fslcl_DirEntry *)NULL) {
  1360.     Output(stderr, "SetDotDot: Could not open dir\n");
  1361.     return(0);
  1362.     }
  1363.     /*
  1364.      * Move past "." to "..".  Note that it is assume that this directory
  1365.      * has been checked and thus has both "." and "..".
  1366.      */
  1367.     NextDirEntry(&dirIndex, &dirEntryPtr);
  1368.     if (dirEntryPtr == (Fslcl_DirEntry *)NULL) {
  1369.     Output(stderr, "SetDotDot: Could not move from . to ..\n");
  1370.     return(0);
  1371.     }
  1372.  
  1373.     descInfoArray[dirNumber].newLinkCount++;
  1374.     descInfoArray[dirNumber].flags |= FD_MODIFIED;
  1375.     dirEntryPtr->fileNumber = dirNumber;
  1376.     if (writeDisk) {
  1377.     if (Disk_FragWrite(partFID, domainPtr, 
  1378.        dirIndex.blockAddr + domainPtr->dataOffset * FS_FRAGMENTS_PER_BLOCK,
  1379.        dirIndex.numFrags, dirIndex.dirBlock) < 0) {
  1380.         Output(stderr, "SetDotDot: Write failed block %d\n",
  1381.             dirIndex.blockAddr + 
  1382.                 domainPtr->dataOffset * FS_FRAGMENTS_PER_BLOCK);
  1383.         return(0);
  1384.     }
  1385.     }
  1386.     return(1);
  1387. }
  1388.  
  1389.  
  1390. /*
  1391.  *----------------------------------------------------------------------
  1392.  *
  1393.  * AddToDirectory --
  1394.  *
  1395.  *    Add the file descriptor to a directory.  
  1396.  *
  1397.  * Results:
  1398.  *    None.
  1399.  *
  1400.  * Side effects:
  1401.  *    The directory is modified to contain the orphaned file.
  1402.  *
  1403.  *----------------------------------------------------------------------
  1404.  */
  1405. static ReturnStatus
  1406. AddToDirectory(dirNumber, dirFDPtr, dirIndexPtr, dirEntryPtrPtr, fileNumber,
  1407.     fileName, fdInfoPtr)
  1408.     int            dirNumber;
  1409.     Fsdm_FileDescriptor    *dirFDPtr;
  1410.     DirIndexInfo    *dirIndexPtr;
  1411.     Fslcl_DirEntry        **dirEntryPtrPtr;
  1412.     int             fileNumber;
  1413.     char         *fileName;
  1414.     register    FdInfo    *fdInfoPtr;
  1415. {
  1416.     int             nameLength;
  1417.     int             recordLength;
  1418.     int             leftOver;
  1419.     int            oldRecLength;
  1420.     Fslcl_DirEntry        *dirEntryPtr;
  1421.     Fsdm_FileDescriptor    *fdPtr;
  1422.  
  1423.     adding = 1;
  1424.     nameLength = strlen(fileName);
  1425.     recordLength = Fslcl_DirRecLength(nameLength);
  1426.  
  1427.     dirEntryPtr = *dirEntryPtrPtr;
  1428.     while (dirEntryPtr != (Fslcl_DirEntry *) NULL) {
  1429.     if (dirEntryPtr->fileNumber != 0) {
  1430.         oldRecLength = Fslcl_DirRecLength(dirEntryPtr->nameLength);
  1431.         leftOver = dirEntryPtr->recordLength - oldRecLength;
  1432.         if (leftOver >= recordLength) {
  1433.         dirEntryPtr->recordLength = oldRecLength;
  1434.         dirEntryPtr = 
  1435.             (Fslcl_DirEntry *) ((int) dirEntryPtr + oldRecLength);
  1436.         dirEntryPtr->recordLength = leftOver;
  1437.         dirIndexPtr->dirOffset += oldRecLength;
  1438.         } else {
  1439.         NextDirEntry(dirIndexPtr, &dirEntryPtr);
  1440.         continue;
  1441.         }
  1442.     } else if (dirEntryPtr->recordLength < recordLength) {
  1443.         NextDirEntry(dirIndexPtr, &dirEntryPtr);
  1444.         continue;
  1445.     }
  1446.  
  1447.     if (!FetchFileDesc(fileNumber, &fdPtr)) {
  1448.         Output(stderr,
  1449.      "Unable to fetch file descriptor for file <%d> to add to directory <%d>\n",
  1450.               fileNumber, dirNumber);
  1451.         return FAILURE;
  1452.     }
  1453.     if (fdInfoPtr->flags & IS_A_DIRECTORY) {
  1454.         if (!SetDotDot(dirNumber, dirFDPtr, fdPtr, fdInfoPtr)) {
  1455.         *dirEntryPtrPtr = dirEntryPtr;
  1456.         return FAILURE;
  1457.         }
  1458.     }
  1459.     fdPtr->numLinks = fdInfoPtr->newLinkCount + 1;
  1460.     fdInfoPtr->flags |= FD_MODIFIED;
  1461.     StoreFileDesc(fileNumber, fdPtr);
  1462.  
  1463.     dirEntryPtr->fileNumber = fileNumber;
  1464.     dirEntryPtr->nameLength = nameLength;
  1465.     dirIndexPtr->dirDirty = 1;
  1466.     (void)strcpy(dirEntryPtr->fileName, fileName);
  1467.     leftOver = dirEntryPtr->recordLength - recordLength;
  1468.     if (leftOver > FSLCL_DIR_ENTRY_HEADER) {
  1469.         dirEntryPtr->recordLength = recordLength;
  1470.         dirEntryPtr =(Fslcl_DirEntry *) ((int) dirEntryPtr + recordLength);
  1471.         dirEntryPtr->fileNumber = 0;
  1472.         dirEntryPtr->recordLength = leftOver;
  1473.         dirIndexPtr->dirOffset += recordLength;
  1474.     } else {
  1475.         NextDirEntry(dirIndexPtr, &dirEntryPtr);
  1476.     }
  1477.     *dirEntryPtrPtr = dirEntryPtr;
  1478.     return SUCCESS;
  1479.     }
  1480.     return DIRFULL;
  1481. }
  1482.  
  1483. /*
  1484.  *----------------------------------------------------------------------
  1485.  *
  1486.  * MakeRoot --
  1487.  *
  1488.  *    Set up the file descriptor for the root directory.
  1489.  *
  1490.  * Results:
  1491.  *    Fill in the file descriptor.
  1492.  *
  1493.  * Side effects:
  1494.  *    Marks block 0 in the bitmap as in use.
  1495.  *
  1496.  *----------------------------------------------------------------------
  1497.  */
  1498. ReturnStatus
  1499. MakeRoot(domainPtr, bitmapPtr, fdPtr)
  1500.     Ofs_DomainHeader        *domainPtr;    /* Ptr to domain info */
  1501.     u_char            *bitmapPtr;    /* Ptr to cylinder data block
  1502.                          * bitmap */
  1503.     Fsdm_FileDescriptor        *fdPtr;
  1504. {
  1505.     Time     time;
  1506.     int     index;
  1507.     u_char     *bytePtr;
  1508.  
  1509.     fdPtr->flags = FSDM_FD_ALLOC;
  1510.     fdPtr->fileType = FS_DIRECTORY;
  1511.     fdPtr->permissions = 0755;
  1512.     fdPtr->uid = 0;
  1513.     fdPtr->gid = 0;
  1514.     fdPtr->lastByte = FS_BLOCK_SIZE-1;
  1515.     fdPtr->firstByte = -1;
  1516.     fdPtr->numLinks = 3;
  1517.     /*
  1518.      * Can't know device information because that depends on
  1519.      * the way the system is configured.
  1520.      */
  1521.     fdPtr->devServerID  -1;
  1522.     fdPtr->devType = -1;
  1523.     fdPtr->devUnit = -1;
  1524.  
  1525.     /*
  1526.      * Set the time stamps.  This assumes that universal time, not local
  1527.      * time, is used for time stamps.
  1528.      */
  1529.     Sys_GetTimeOfDay(&time, NULL, NULL);
  1530.     fdPtr->createTime = time.seconds;
  1531.     fdPtr->accessTime = 0;
  1532.     fdPtr->descModifyTime = time.seconds;
  1533.     fdPtr->dataModifyTime = time.seconds;
  1534.  
  1535.     /*
  1536.      * Place the data in the first filesystem block.
  1537.      */
  1538.     fdPtr->direct[0] = 0;
  1539.     bytePtr = GetBitmapPtr(domainPtr, bitmapPtr, 0);
  1540.     *bytePtr |= 0xf0;
  1541.     for (index = 1; index < FSDM_NUM_DIRECT_BLOCKS ; index++) {
  1542.     fdPtr->direct[index] = FSDM_NIL_INDEX;
  1543.     }
  1544.     for (index = 0; index < FSDM_NUM_INDIRECT_BLOCKS ; index++) {
  1545.     fdPtr->indirect[index] = FSDM_NIL_INDEX;
  1546.     }
  1547.     fdPtr->numKbytes = 4;
  1548.     fdPtr->version = 1;
  1549.     return SUCCESS;
  1550. }
  1551.  
  1552. /*
  1553.  *----------------------------------------------------------------------
  1554.  *
  1555.  * strnlen --
  1556.  *
  1557.  *    This is identical to strlen except that it will return N
  1558.  *    if the string length reaches N.
  1559.  *
  1560.  * Results:
  1561.  *    The return value is the number of characters in the
  1562.  *    string, not including the terminating zero byte.
  1563.  *
  1564.  * Side effects:
  1565.  *    None.
  1566.  *
  1567.  *----------------------------------------------------------------------
  1568.  */
  1569. int
  1570. strnlen(string, numChars)
  1571.     register char *string;        /* String whose length is wanted. */
  1572.     int           numChars;        /* Maximum number of chars to check. */
  1573. {
  1574.     register int result = -1;
  1575.  
  1576.     do {
  1577.     result += 1;
  1578.     } while (result < numChars && *string++ != 0);
  1579.     return(result);
  1580. }
  1581.